/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model.gestion_jeu;

import connection_reseau.ConnectionReseau;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Observable;
import java.util.Stack;
import model.serialisation.Serialisateur;
import model.jeu_de_dame.Piece;
import model.jeu_de_dame.Damier;
import model.util.Couleur;
/**
 *
 * @author ANNAS
 */
public class AdaptateurReseau extends Observable{
    private static String adresseServeurJeu = "";
    private static int port = 0;
    ConnectionReseau serveur;
    ConnectionReseau joueur;
    Stack<ConnectionReseau> listeConnectionEntrante;
    Serialisateur s;
    ArrayList<String> laListe;
    String nomJoueur;
    
    
    private static AdaptateurReseau instance;
    
    /**
     * Récupération de l'instance
     */
    public static AdaptateurReseau getInstance()
    {
        if(instance==null)
            instance = new AdaptateurReseau();
        return instance;
    }
    
    private AdaptateurReseau() {
        
    }
    
    /**
     * Charge la liste des joueurs disponibles sur le réseau avec qui l'utilisateur peut jouer
     */
    public void chargerListeJoueursEnReseau()
    {
        String requete="";
        serveur.write(requete);
        Object o = serveur.read();
        try{
            
            laListe = (ArrayList<String>)o;
            this.setChanged();
            this.notifyObservers();
        }catch(Exception e)
        {
            laListe= new ArrayList<String>();
        }
        
    }
    
    /**
     * Récupération de la liste des joueurs disponibles sur le réseau avec qui l'utilisateur peut jouer
     * @return  
     *      Retourne la liste des joueurs
     */
    public ArrayList<String> getListeJoueursEnReseau() {
        chargerListeJoueursEnReseau();
        return laListe;
    }
    
    
    
    /**
     * Initialise et démarre la partie en réseau
     * @param numeroJoueur
     *          numero du joueur
     */
    public Partie demarrerJeuEnReseau(int numeroJoueur) throws Exception
    {
        String requete="getInfoJoueur",adresse="",nomReseau="";int port=0;
        serveur.write(requete+numeroJoueur);
        Object o = serveur.read();
        try{
          HashMap<String,Object> res= (HashMap<String,Object>) s.deserialiser(o);
          adresse = (String)res.get("adresse");
          port = (int)((Integer)res.get("port"));
          nomReseau = (String)res.get("nom");
        }catch(Exception e)
        {
            throw new Exception("erreur creation partie");
        }
        if(joueur.connection(adresse, port))
        {
            PartieReseau pr = new PartieReseau(nomJoueur, nomReseau, true);
            synchronisation(pr, pr.getDamier(), pr.getJoueurLocal(), pr.getJoueurReseau());
            receptionMaj(pr);
            return pr;
        }
        else
            throw new Exception("Connection impossible");
    }
    
     /**
     * Met à jour les informations après un déplacement
     * @param xCase
     *         position x de la case
     * @param yCase 
     *         position y de la case
     * @param p
     *         Piece sur la case
     * @return 
     *         Retourne vrai s'il est possible de déplacer
     *         Retourne faux sinon
     */   
    public boolean majDeplacement(int xCase, int yCase, Piece p)
    {
        HashMap<String,Object> lesInfos = new HashMap<String,Object>();
        lesInfos.put("commande", "majDeplacement");
        lesInfos.put("xCase", xCase);
        lesInfos.put("yCase", yCase);
        lesInfos.put("piece", p);
        String message = s.serialiser(lesInfos);
        String resultat ="";
        if(joueur.write(message)){
            HashMap<String,Object>res = (HashMap<String,Object>)s.deserialiser(joueur.read());
            String ack = "ack";
            resultat = (String)res.get((Object)ack);
        }
        if(resultat.equalsIgnoreCase("ok"))
            return true;
        
        return false;   
    }
    
     /**
     * Synchronise la partie des deux joueurs
     * @param p
     *          instance de la partie
     * @param d
     *          instance du damier
     * @param local     
     *          Joueur local
     * @param reseau
     *          Joueur adverse trouvé sur le réseau
     */
    public boolean synchronisation(Partie p, Damier d,Joueur local,Joueur reseau)
    {
        HashMap<String,Object> lesInfos = new HashMap<String,Object>();
        lesInfos.put("commande", "synchro");
        lesInfos.put("partie", p);
        lesInfos.put("damier", d);
        lesInfos.put("joueur_local", local);
        lesInfos.put("joueur_reseau", reseau);
        String message = s.serialiser(lesInfos);
        String resultat ="";
        if(joueur.write(message)){
            HashMap<String,Object>res = (HashMap<String,Object>)s.deserialiser(joueur.read());
            String ack = "ack";
            resultat = (String)res.get((Object)ack);
        }
        if(resultat.equalsIgnoreCase("ok"))
            return true;
        
        return false;   
    }
    
    //un thread ecoutera en permanence les maj provenant de l exterieur et avertira soir les vues via notify
    //soit la partie
    
     /**
     * Un thread ecoute en permanence les maj provenant de l'exterieur puis avertit soit les vues avec notify soit la partie
     * @param p
     *          instance de la partie
     */
    public synchronized  void receptionMaj(Partie p)
    {
        while(true)
        {
            HashMap<String,Object>res = (HashMap<String,Object>)s.deserialiser(joueur.read());
            String com = "commance";
            String resultat = (String)res.get((Object)com);
            if(com.equalsIgnoreCase("synchro"))
            {
                
            }else if(com.equalsIgnoreCase("fin"))
            {
                
            }else if(com.equalsIgnoreCase("majDeplacement"))
            {
                
            }else if(com.equalsIgnoreCase("demarrer"))
            {
                
            }
            this.setChanged();
            this.notifyObservers();
        }
    }
    
    
     /**
     * Un thread ecoute en permanence s'il y'a une connexion entrante. Listen est bloquante
     */
    public synchronized  void ecouteConnexionEntrante()
    {
        while(true)
        {
            ConnectionReseau c = serveur.listen();
            listeConnectionEntrante.add(c);
            this.setChanged();
            this.notifyObservers();
        }
        
    }

     /**
     * Accepte une connexion entre 2 joueurs
     * @return
     *      renvoie la partie 
     */
    public Partie acceptConnexion() throws Exception
    {
        if(!listeConnectionEntrante.isEmpty())
        {
            joueur = listeConnectionEntrante.pop();
            String nomJoueurReseau="";
            PartieReseau pr = new PartieReseau(nomJoueurReseau, nomJoueur, false);
            synchronisation(pr, pr.getDamier(), pr.getJoueurLocal(), pr.getJoueurReseau());
            receptionMaj(pr);
            return pr;
        }
        throw new Exception("Pas de connexion");
    }

     /**
     * Récupère la liste des connections entrantes
     * @return 
     *      Liste des connection entrante
     */
    public Stack<ConnectionReseau> getListeConnectionEntrante() {
        return listeConnectionEntrante;
    }
    
     /**
     * Lors d'une connexion, on récupère le nom du joueur s'il n'a pas déjà été enregistré. 
     * On ajoute le numéro à la liste des personnes connectées
     * @param nomJoueur
     *          Nom du joueur entrant
     * @return
     *          Retourne vrai si le nom est nouveau
     *          Retourne faux sinon
     */
    public boolean enregistrerJoueur(String nomJoueur)
    {
        serveur.connection(AdaptateurReseau.adresseServeurJeu, AdaptateurReseau.port);
        serveur.write("enregistrer"+nomJoueur);
        listeConnectionEntrante = new  Stack<ConnectionReseau>();
        return true;
    }
    
    
}
